package com.btw;

import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Queue;
import java.util.Random;
import java.util.Set;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.view.MotionEvent;

/**
 * simple updater thread 
 * @author TannerMeans
 *
 */
class Updater implements Runnable {
	
	// View this updater corresponds to
	private final GLSurfaceView mGLView;
	private Queue<MotionEvent> events;
	
	// Screen constants
	public static final int CONTROL_WIDTH = 100;
	public Set<Coordinates> ballLocations;
	
	// Time constants
	private static final int TICKS_PER_SECOND = 25;
	private static final int SKIP_TICKS = 1000/ TICKS_PER_SECOND;
	private static final int MAX_FRAMESKIP = 10;
	private static final double fps = 2; //~2 fps, this didn't come out quite as planned. Almost accurate
	private static final int animationSkip = (int) (TICKS_PER_SECOND / (fps * .005));
	
	// Util objects
	private static final Random r = new Random();	// might as well not generate this a ton and put it up here
	
	// Screen objects
	private final VSRenderer renderer;
	private Group meshes;				// a group of all the meshes we want to render
	private Group balls;				// a group of all balls
	
	private SimplePlane background;
	//private Ball ball;
	
	// textures
	private Map<String, Bitmap> textures;
	private long startTime;
	private long currentTick;
	private long lastTick;
	private long timePassed;
	private long next_game_tick;
	

	public Updater(GLSurfaceView mGLView, Context c) {
		this.mGLView = mGLView;
		this.events = ((VSView) mGLView).events;
		
		
		// initialize Groups
		meshes = new Group();
		balls = new Group();
		
		ballLocations = new HashSet<Coordinates>();
		
		textures = loadTextures();
		
		renderer = new VSRenderer(meshes);
		mGLView.setRenderer(renderer);
		
	
		initGame();
	}

	public void run() {
		// initialize time vars here. need to be as close to the game start as possible
				startTime = getTickCount();
				currentTick = 0;
				lastTick = 0;
				int loops = 0;
				
				// memory placeholders (helps with GC)
				Iterator<Mesh> meshIter;
				
				Ball singleBall;
				
				gameloop: // designates the game is running
				while (true) { // game is running 
					handleEvents(); // look for any touch events
				
					loops = 0;
					while(getTickCount() > next_game_tick && loops < MAX_FRAMESKIP) {
						
						// update game 
						lastTick = currentTick;
						currentTick = getTickCount();
						timePassed = currentTick - lastTick;
					}
					/*
					meshIter = balls.iterator();
					while(meshIter.hasNext()) {
						singleBall = (Ball)meshIter.next();
						
					}
					*/
				}
				
				// game over
				//save final game vars
				//gameIsOver();
	}
	
	private void initGame() {
		// load background
		background = new SimplePlane(0, 0, 800+(1024-800), 480+(512-480)); //don't want to deal with stretching the texture... so I'll make the object big
		background.loadBitmap(textures.get("Background"));
		meshes.add(background);
		
		// load control background
		SimplePlane controlSpace = new SimplePlane(0, 0, CONTROL_WIDTH, 480);
		controlSpace.setColors(new float[] {
                0f, 0f, 0f, 1f, //
                0f, 0f, 0f, 1f, //
                0f, 0f, 0f, 1f, //
                0f, 0f, 0f, 1f, //
        });
		meshes.add(controlSpace);
		
		/*
		Ball m = new Ball(0, 0);
		
		m.loadBitmap(textures.get("Ball"));
		meshes.add(m);
		balls.add(m);
		*/
		
		// load initial Balls
		for (int i = 0; i < 20; i ++) {
			generateBall();
		}
		
		
		
	}
	
		public void generateBall() {
			boolean overlap = true;
			float ballX = 0;
			float ballY = 0;
			
			// specify constraints on the placement of the monsters (no overlapping, etc)
			while (overlap) {
				overlap = false;
				ballX = r.nextFloat()*(800-Ball.M_DIAMETER); //no monsters off the right of the screen
				ballY = r.nextFloat()*(480-Ball.M_DIAMETER); //no monsters off the bottom of the screen
				if (ballLocations.size() == 0 &&
						(ballX <= VSView.CONTROL_WIDTH + Ball.M_DIAMETER/2 //no monsters in control area, nor off the left of the screen
						|| ballY <= Ball.M_DIAMETER/2 )) { //no monsters off the top of the screen)
					overlap = true;
				}
				for (Coordinates coords : ballLocations) {
					if (!overlap && //if we have overlapped one monster, we're overlapping already (so we don't want to check and accidentally set overlap back to false)
							((ballX >= coords.x - Ball.M_DIAMETER &&  
							ballX <= coords.x + Ball.M_DIAMETER && 
							ballY >= coords.y - Ball.M_DIAMETER &&  
							ballY <= coords.y + Ball.M_DIAMETER) //no monsters on top of each other 
							|| ballX <= VSView.CONTROL_WIDTH + Ball.M_DIAMETER/2 //no monsters in control area, nor off the left of the screen
						
							|| ballY <= Ball.M_DIAMETER/2 )) { //no monsters off the top of the screen
						overlap = true;
					}
				}
			}
			// we aren't overlapping, so make the monster
			ballLocations.add(new Coordinates(ballX, ballY));
			Ball m = new Ball(
					ballX,
					ballY);
			
			m.loadBitmap(textures.get("Ball"));
			meshes.add(m);
			balls.add(m);
		}

	/**
	 * Game over, save data and go to next level
	 * @return
	 */
	private void gameIsOver() {
		
		
	}
	
	/**
	 * loads all the textures into memory again
	 * @return
	 */
	public Map<String, Bitmap> loadTextures() {
		Map<String, Bitmap> newTextures = new HashMap<String, Bitmap>();
		Resources newRes = mGLView.getResources();
		
		newTextures.put("Background", BitmapFactory.decodeResource(newRes, R.drawable.background));
		newTextures.put("Ball",BitmapFactory.decodeResource(newRes, R.drawable.ball));
		
		return newTextures;
	}
	
	/**
	 * @return the current number of milliseconds
	 * that have elapsed since the system was started
	 */
	private long getTickCount() {
		return (new Date()).getTime();
	}
	
	public boolean handleClick(MotionEvent event) {
		int action = event.getAction();
		
		// screen coords
		float clickX = event.getX();
		float clickY = event.getY();
		
			if (action == MotionEvent.ACTION_DOWN) {
				//Log.d("EVENT_DOWN", "single clicked: (" + clickX + "," + clickY + ")");
				if(checkBallClicked(clickX, clickY)) {
					return true;
				}
			}
		
		return true;
	}
	
	private boolean checkBallClicked(float clickX, float clickY) {
		Iterator<Mesh> iter = balls.iterator();
		Mesh ball;
		while(iter.hasNext()) {
			ball = iter.next();
			if(ball.containsPoint(clickX, clickY)) {
				iter.remove();
				meshes.remove(ball);
			}
			return true;
		}
		
		return false;
	}

	private void handleEvents() {
		while (events.size() > 0) {
			handleClick(events.remove());
		}
	}
	
}
